﻿#include "ssAsioSession.h"
#include "log/ssLogThread.h"
#include "ssAsioNetWork.h"

namespace StarSeeker
{

ssAsioSession::ssAsioSession(void)
{
	m_timeCheck = false;
	m_lastTime = 0;
	m_fastCount = 0;
	m_checkCount = 20;
	m_intervalTime = 100;
	m_sessionID = 0;
	m_pNetMgr = 0;
	m_sending = false;
	m_fullCount = 0;
}

ssAsioSession::~ssAsioSession(void)
{
	m_timeCheck = false;
	m_lastTime = 0;
	m_fastCount = 0;
	m_checkCount = 20;
	m_intervalTime = 100;
	m_sessionID = 0;
	m_pNetMgr = 0;
	m_fullCount = 0;
}

bool ssAsioSession::Init(u32 id, SS_SHARED_PTR<asio::ip::tcp::socket>& socket, u32 recvBuffSize, u32 sendBuffSize, ssAsioNetWork* pNetMgr)
{
	m_sessionID = id;
	m_pNetMgr = pNetMgr;
	if (!m_socket)
	{
		m_recvBuf.Init(recvBuffSize);
		m_socket = socket;
		try
		{
			m_socket->set_option(asio::socket_base::receive_buffer_size(recvBuffSize));
			m_socket->set_option(asio::socket_base::send_buffer_size(sendBuffSize));
			m_socket->set_option(asio::socket_base::keep_alive(true));
			m_ip = m_socket->remote_endpoint().address().to_string();
			return true;
		}
		catch (asio::error_code& e)
		{
		}
		catch (...)
		{
		}
	}
	return false;
}

void ssAsioSession::SetTimeCheck(bool timeCheck, i64 intervalTime /*= 100*/, u16 checkCount /*= 20*/)
{
	m_timeCheck = timeCheck;
	m_intervalTime = intervalTime;
	m_checkCount = checkCount;
}

void ssAsioSession::Close(eAsioClose errType, i32 err)
{
	if (m_pNetMgr)
	{
		m_pNetMgr->DoCloseSocket(m_sessionID, errType, err);
	}
}

SS_SHARED_PTR<asio::ip::tcp::socket>& ssAsioSession::GetSocket()
{
	return m_socket;
}

bool ssAsioSession::OnReceive()
{
	if (m_timeCheck)
	{
		i64 now = ssTime::GetTimeNowMS().i64p;
		if (now - m_lastTime < m_intervalTime)//太频繁
		{
			++m_fastCount;
		}
		else
		{
			m_fastCount = 0;
		}
		m_lastTime = now;
		if (m_fastCount > m_checkCount)//超过20次断线
		{
			Close(CLOSE_BY_READ_FAST, 0);
			return false;
		}
	}

	return ParseData() == PARSE_TOO_MANY;
}

eParseState ssAsioSession::ParseData()
{
	if (m_recvBuf.Size() > 0)
	{
		if (m_recvBuf.IsFull())
		{
			SS_LOG->PrintEx("%u recvBuf is full", m_sessionID);
		}

		char* buf = m_recvBuf.Buf();
		ulint len = m_recvBuf.Size();
		ulint readSize = 0;
		//u32 runCt = 0;
		while (1/*runCt++ < 800*/)
		{
			if (len < MSG_BASIC_HEADER_LEN)
			{
				break;
			}

			if(len > MSG_MAX_SIZE)
			{
				m_recvBuf.Empty(false);
				SS_LOG->ErrorEx("%u PARSE DISCARD", m_sessionID);
				return PARSE_DISCARD;
			}
			ssNetMsgBasicHead* head = (ssNetMsgBasicHead*)buf;
			//check msg
			if (head->m_dwTcpFlag != MSG_HEADER_FLAG || head->m_dwLen > MSG_MAX_SIZE || head->m_dwLen < MSG_BASIC_HEADER_LEN)
			{
				m_recvBuf.Empty(false);
				SS_LOG->ErrorEx("%u PARSE DISCARD", m_sessionID);
				return PARSE_DISCARD;
			}
			if (len < head->m_dwLen)
			{
				break;
			}
			if (m_pNetMgr)
			{
				char* tempBuff = CopyMsgFromRecvBuffer(head);
				if (tempBuff)
				{
					//抛到上层，其他线程调用时session对象可能已经删除，使得变为野指针
					m_pNetMgr->OnSessionMessage(*this, head->m_dwMsgID, tempBuff);
				}
			}
			readSize += head->m_dwLen;
			buf += head->m_dwLen;
			len -= head->m_dwLen;
		}
		m_recvBuf.MoveForward(readSize);
		if (m_recvBuf.Size())
		{
			return /*runCt >= 800 ? PARSE_TOO_MANY :*/ PARSE_WAIT;
		}
	}
	return PARSE_NOTHING;
}

char* ssAsioSession::CopyMsgFromRecvBuffer(ssNetMsgBasicHead* msg)
{
	//!!需要对象池
	char* tempBuff = new char[msg->m_dwLen];
	memcpy(tempBuff, msg, msg->m_dwLen);
	return tempBuff;
}

}
